import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.StringTokenizer;

public class Conveyor implements Runnable {
    private void solve() {
		int numBlocks = nextInt();
		int blockSize = nextInt();
		int numOps = nextInt();
		long[] blocks = new long[numBlocks];
		long[] tmp = new long[numBlocks];
		long[] res = new long[4];
		long total = 0;
		for (int opIndex = 0; opIndex < numOps; ++opIndex) {
			String opKind = nextToken();
			switch (opKind.charAt(0)) {
				case '>': {
					int repetitions = nextInt();
					String seq = nextToken();
					int seqLength = seq.length();
					long seqBinary = Long.parseLong(seq, 2);
					total += repetitions * Long.bitCount(seqBinary);
					long[] cur = new InnerSolver(numBlocks, blockSize, repetitions, seqLength, seqBinary, blocks).doit();
					res[0] += cur[0];
					res[2] += cur[1];
					break;
				}
				case '<': {
					int repetitions = nextInt();
					int seqLength = 1;
					long seqBinary = 0;
					for (int i = 0; i < numBlocks; ++i)
						tmp[i] = Long.reverse(blocks[numBlocks - 1 - i]) >>> (64 - blockSize);
					long[] cur = new InnerSolver(numBlocks, blockSize, repetitions, seqLength, seqBinary, tmp).doit();
					for (int i = 0; i < numBlocks; ++i)
						blocks[i] = Long.reverse(tmp[numBlocks - 1 - i]) >>> (64 - blockSize);
					res[1] += cur[0];
					res[2] += cur[1];
					break;
				}
				default:
					throw new RuntimeException();
			}
			//dump(numBlocks, blockSize, blocks);
		}
		res[3] = total - res[0] - res[1] - res[2];
		writer.println(res[0] + " " + res[1] + " " + res[2] + " " + res[3]);
    }

	private void dump(int numBlocks, int blockSize, long[] blocks) {
		for (int i = 0; i < numBlocks; ++i) {
			String s = Long.toString(blocks[i], 2);
			while (s.length() < blockSize) s = "0" + s;
			writer.print(s + " ");
		}
		writer.println();
	}

	private static class InnerSolver {
		private final int numBlocks;
		private final int blockSize;
		private final int repetitions;
		private final int seqLength;
		private long seqBinary;
		private final long[] blocks;

		public InnerSolver(int numBlocks, int blockSize, int repetitions, int seqLength,
				long seqBinary, long[] blocks) {
			this.numBlocks = numBlocks;
			this.blockSize = blockSize;
			this.repetitions = repetitions;
			this.seqLength = seqLength;
			this.seqBinary = seqBinary;
			this.blocks = blocks;
		}

		public long[] doit() {
			long[] res = new long[2];
			for (long x : blocks)
				res[0] += Long.bitCount(x);
			long[] blockStack = new long[numBlocks + 1];
			blockStack[0] = Long.MAX_VALUE / 2;
			int blockStackPointer = 1;
			for (int blockId = numBlocks - 2; blockId >= 0; --blockId) {
				blockStack[blockStackPointer++] = (blockId + 1) * blockSize;
				while (blocks[blockId] != 0) {
					int lastBit = Long.numberOfTrailingZeros(blocks[blockId]);
					long lastBitPos = (blockSize - 1 - lastBit) + blockId * blockSize;
					if (lastBitPos + repetitions * seqLength >= blockStack[blockStackPointer - 1]) {
						blocks[blockId] ^= (1L << lastBit);
						--blockStackPointer;
						++res[1];
					} else {
						break;
					}
				}
			}
			int numLastKilled = 0;
			long lastSeqBinary = seqBinary;
			int numSeqOnes = Long.bitCount(seqBinary);
			while (numLastKilled < repetitions * numSeqOnes) {
				int lastBit = Long.numberOfTrailingZeros(lastSeqBinary);
				long lastBitPos = -(lastBit + seqLength * (numLastKilled / numSeqOnes)) - 1;
				if (lastBitPos + repetitions * seqLength >= blockStack[blockStackPointer - 1]) {
					++numLastKilled;
					lastSeqBinary ^= (1L << lastBit);
					if (lastSeqBinary == 0) lastSeqBinary = seqBinary;
					--blockStackPointer;
					++res[1];
				} else {
					break;
				}
			}
			int numLastKilledBlocks;
			if (numLastKilled == repetitions * numSeqOnes) {
				seqBinary = 0;
				numLastKilled = 0;
				lastSeqBinary = 0;
				numLastKilledBlocks = 0;
			} else {
				numLastKilledBlocks = numLastKilled / numSeqOnes;
			}
			BitStack stack = new BitStack(numBlocks, blockSize);
			int normalBlocks = repetitions - numLastKilledBlocks - 1;
			int largeCopyCount = 60 / seqLength;
			long largeCopy = 0;
			for (int i = 0; i < largeCopyCount; ++i)
				largeCopy |= seqBinary << (i * seqLength);
			for (int i = 0; i < normalBlocks; ++i) {
				if (i + largeCopyCount <= normalBlocks) {
					if (stack.push(largeCopy, largeCopyCount * seqLength)) break;
					i += largeCopyCount - 1;
				} else {
					if (stack.push(seqBinary, seqLength)) break;
				}
			}
			stack.push(lastSeqBinary, seqLength);
			for (int i = 0; i < numLastKilledBlocks; ++i) {
				if (i + largeCopyCount <= numLastKilledBlocks) {
					if (stack.push(0, largeCopyCount * seqLength)) break;
					i += largeCopyCount - 1;
				} else {
					if (stack.push(0, seqLength)) break;
				}
			}
			for (int i = 0; i < numBlocks; ++i) {
				if (stack.push(blocks[i], blockSize)) break;
			}
			System.arraycopy(stack.blocks, 0, blocks, 0, blocks.length);
			res[0] -= res[1];
			res[0] += repetitions * numSeqOnes;
			for (long x : blocks)
				res[0] -= Long.bitCount(x);
			return res;
		}

		static class BitStack {
			long[] blocks;
			private final int numBlocks;
			private final int blockSize;
			int pos = 0;

			public BitStack(int numBlocks, int blockSize) {
				this.numBlocks = numBlocks;
				this.blockSize = blockSize;
				blocks = new long[numBlocks];
			}

			public boolean push(long mask, int size) {
				while (size > 0) {
					int curIndex = pos / blockSize;
					if (curIndex >= numBlocks) return true;
					int freeBits = blockSize - (pos % blockSize);
					if (freeBits >= size) {
						blocks[curIndex] |= mask << (freeBits - size);
						pos += size;
						size = 0;
						mask = 0;
					} else {
						blocks[curIndex] |= mask >>> (size - freeBits);
						mask &= (1L << (size - freeBits)) - 1;
						size -= freeBits;
						pos += freeBits;
					}
				}
				if (pos / blockSize >= numBlocks) return true;
				return false;
			}
		}
	}


	public static void main(String[] args) {
        new Conveyor().run();
    }

    BufferedReader reader;
    StringTokenizer tokenizer;
    PrintWriter writer;

    static final String TASK_ID = "conveyor";

    public void run() {
        try {
            reader = new BufferedReader(new FileReader(TASK_ID + ".in"));
            tokenizer = null;
            writer = new PrintWriter(TASK_ID + ".out");
            solve();
            reader.close();
            writer.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    int nextInt() {
        return Integer.parseInt(nextToken());
    }

    long nextLong() {
        return Long.parseLong(nextToken());
    }

    double nextDouble() {
        return Double.parseDouble(nextToken());
    }

    String nextToken() {
        while (tokenizer == null || !tokenizer.hasMoreTokens()) {
            try {
                tokenizer = new StringTokenizer(reader.readLine());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken();
    }

}
